#!perl -w

use SOAP::Lite;

use strict;

# EXAMPLE NOTES
#
# See the three constants immediately following these notes.  You'll probably 
# have to change all of them.
#
# Notes:
#  - The username and password are set by overriding the 
#    SOAP::Transport::HTTP::Client::get_basic_credentials method
#
#  - SOAP::Lite uses RPC (section 5) encoding by default.  The examples use
#    a custom serializer to make it easier to compose requests to the WCCA2
#    Web service.  See Example::Serializer for more information.  It doesn't
#    include type information and provides two (mixed_content and simpledate)
#    serializers that are useful in making WCCA2 requests.
#
#  - Each example is intended to show a slightly different use case:
#    - run_case_search_1 - Nests one object in another (a case range "bean"
#      inside of a case search query).
#    - run_case_search_3 - A simple party search.
#    - run_atty_calendar_search - Searches on a date field.  Commented out 
#      code in this method also demonstrates how to send raw XML in the 
#      message body.
#    - retrieve_criminal_case - Retrieves a criminal case.  
#    - retrieve_civil_case - Retrieves a civil case.  This example also makes
#      use of the SOAP::Custom::XML::Deserializer class.
#

# set this to your user name
my $USER = "exampleuser";

# set this to your password
my $PASSWORD = "examplepass1/examplepass2";

# the service location of the WCCA2 service
my $SERVICE_LOC = 'http://wcca.wicourts.gov/services/WCCA2';

# the XML namespace used by the WCCA2 service. Don't change this.
my $SERVICE_NS = 'urn:soap.wcca2.ccap.courts.state.wi.us';

# prototypes for example searches
sub run_case_search_1;
#sub run_case_search_2;
sub run_case_search_3;
sub run_atty_calendar_search;
#sub run_docketed_cv_jdgmt_report;
sub retrieve_criminal_case;
sub retrieve_civil_case;

# prototypes for helper methods
sub call_case_search;
sub dump_case_list;
sub get_method;
sub make_soap_call;
sub format_name;

# returns the user name and password for the service
sub SOAP::Transport::HTTP::Client::get_basic_credentials { 
   return $USER => $PASSWORD;
}

# create the service object
my $soap = SOAP::Lite
    ->uri($SERVICE_NS)
    ->proxy($SERVICE_LOC)
    ->serializer(Example::Serializer->new)
    ->readable(1);

# run the example searches
retrieve_civil_case $soap;
run_case_search_1 $soap;
run_case_search_3 $soap;
run_atty_calendar_search $soap;
retrieve_criminal_case $soap;

sub retrieve_criminal_case {
    my $soap = shift;

    my $param = SOAP::Data->type('mixed_content')->name('input')->value(
        [ SOAP::Data->name(caseNo => '2002CF000057'),
          SOAP::Data->name(countyNo => 44 )]);

    print "Retrieving criminal case 01CF57 in county 44 (Outagamie)\n";

    my $som = make_soap_call $soap, 'retrieveCriminalCase', $param;
    if ($som) {
        print "--------\n";
        my $case = $som->valueof(
            '/Envelope/Body/retrieveCriminalCaseResponse/' .
            'CriminalCaseDetailsResult');
        print "Defendant name is " . format_name($case->{defendant}) . "\n";
        print "Charges:\n";

        my @charges = $som->valueof(
            '/Envelope/Body/retrieveCriminalCaseResponse/' .
            'CriminalCaseDetailsResult/chargeList');

        foreach my $charge (@charges) {
            print "    " . $charge->{descr} . "\n";
        }
        print "--------\n";
    }
}

sub retrieve_civil_case {
    my $soap = shift;

    my $old_deserializer = $soap->deserializer;

    $soap->deserializer(SOAP::Custom::XML::Deserializer->new);

    my $param = SOAP::Data->type('mixed_content')->name('input')->value(
        [  SOAP::Data->name(caseNo => '2001SC000384'),
           SOAP::Data->name(countyNo => 44)]);

    print "Retrieving civil case 01SC384 from county 44 (Outagamie)\n";

    my $som = make_soap_call $soap, 'retrieveCivilCase', $param;
    if ($som) {
        print "--------\n";

        my $case = $som->valueof(
            '/Envelope/Body/retrieveCivilCaseResponse/' .
            'CivilCaseDetailsResult');

        print "Parties:\n";

        foreach my $party ($case->civilCasePartyList) {
            print "    " . format_name_custom_deser($party) . 
                " - " . $party->partyTypeDescr . "\n";
        }

        print "\nCivil Judgments:\n";

        foreach my $jdgmt ($case->civilJdgmtDetailList) {
            print "    Total Amount: " . $jdgmt->totAmt . "\n";
            print "    Debtors\n";
            foreach my $party ($jdgmt->civilJdgmtPartyList) {
                print "        " . format_name_custom_deser($party) . "\n" 
                    if $party->descr eq "Debtor";
            }
        }
            
        print "--------\n";
    }

    $soap->deserializer($old_deserializer);
}

sub run_case_search_1 {
    my $soap = shift;

    my $param = SOAP::Data->type('mixed_content')->name('input')->value(
        [ SOAP::Data->name(countyNo => 44),
          SOAP::Data->type('mixed_content')->name('caseRange')->value(
              [ SOAP::Data->name(year => '2001'),
                SOAP::Data->name(caseType => 'CF'),
                SOAP::Data->name(start => 50),
                SOAP::Data->name(end => 60) ])]);

    call_case_search $soap, $param;
}


sub run_case_search_3 {
    my $soap = shift;

    my $param = SOAP::Data->type('mixed_content')->name('input')->value(
        [ SOAP::Data->type('mixed_content')->name('partyName')->value(
              [ SOAP::Data->name(lastName => "brant"),
                SOAP::Data->name(firstName => "peter") ])]);

    call_case_search $soap, $param;
}

sub run_atty_calendar_search {
    my $soap = shift;

    my $method = get_method 'searchAttyCalendars';

    my $param = SOAP::Data->type('mixed_content')->name('input')->value(
        [ SOAP::Data->name(attyNo => '1015378'),
        SOAP::Data->name(attyType => 'prosAtty'),
        SOAP::Data->name(date => 
            SOAP::Data->type(simpledate => {year=>2003, month=>3, day=>24})),
        SOAP::Data->name(range => 7) ]
        );

    # Simple, but effective 
    #my $param = SOAP::Data->type('xml' =>
    # q!
    # <searchAttyCalendars xmlns="urn:soap.wcca2.ccap.courts.state.wi.us">
    #    <attyNo>1015378</attyNo>
    #    <attyType>prosAtty</attyType>
    #    <date>2003-03-24T00:00:00.0000000+00:00</date>
    #    <range>7</range>
    # </searchAttyCalendars>
    # !);
    
    print "Running attorney calendar search\n";

    my $som = $soap->call($method, $param);

    if ($som->fault) {
        print "Call failed\n";
        print $som->faultcode . "\n";
        print $som->faultstring . "\n";
    } else {
        my @records = $som->valueof(
            '/Envelope/Body/searchAttyCalendarsResponse/' .
            'AttorneyCalendarSearchResult/attorneyCalendarList');

        print "--------\n";
        print "Retrieved " . scalar @records . " records\n";
        foreach my $calendar (@records) {
            printf "%s at %s on %s\n", 
                $calendar->{descr}, 
                substr($calendar->{startTime}, 0, 8), 
                substr($calendar->{calDate}, 0, 10);
        }
        print "--------\n";
    }
}

sub format_name_custom_deser {
    my $obj = shift;

    my %hash;

    $hash{nameF} = $obj->nameF;
    $hash{nameM} = $obj->nameM;
    $hash{nameL} = $obj->nameL;
    $hash{suffix} = $obj->suffix;

    return format_name \%hash;
}

sub format_name {
    my $hash = shift;
    
    my $result = "";

    unless ($hash->{nameL}) {
        return '';
    } else {
        $result .= $hash->{nameL};
    }

    $result .= " " 
        if ($hash->{nameF} || $hash->{nameM} || $hash->{suffix});
    $result .= $hash->{nameF} if $hash->{nameF};
    $result .= " " if ($hash->{nameM} || $hash->{suffix});
    $result .= $hash->{nameM} if $hash->{nameM};
    $result .= " " if ($hash->{suffix});
    $result .= $hash->{suffix} if $hash->{suffix};

    return $result;    
}

sub make_soap_call {
    my ($soap, $methodName, $param) = @_;

    my $method = get_method $methodName;

    my $som = $soap->call($method, $param);

    if ($som->fault) {
        print "Call failed\n";
        print $som->faultcode . "\n";
        print $som->faultstring . "\n";
    } else {
        return $som;
    }    
}

sub call_case_search {
    my ($soap, $param) = @_;

    my $method = get_method 'searchCases';

    print "Running sample case search\n";

    my $som = $soap->call($method, $param);

    if ($som->fault) {
        print "Call failed\n";
        print $som->faultcode . "\n";
        print $som->faultstring . "\n";
    } else {
        my @records = $som->valueof(
            '/Envelope/Body/searchCasesResponse/' .
            'CaseSearchResult/caseInfoList');
        dump_case_list \@records;
    }
}

sub dump_case_list {
    my $records = shift;

    print "--------\n";
    print "Retrieved " . @$records . " results\n";
    foreach my $case (@$records) {
        printf "%-15s %s\n", $case->{caseNo}, $case->{caption};
    }
    print "--------\n";
}

sub get_method
{
    my $name = shift;

    return SOAP::Data->name($name)
        ->attr({xmlns => $SERVICE_NS});
}

BEGIN {

# Custom serializer to make it easier to produce document/literal
# requests
package Example::Serializer;

@Example::Serializer::ISA = 'SOAP::Serializer';

# Identical to SOAP::Serializer::as_string, but does not include
# type information
sub as_string {
  my $self = shift;
  my($value, $name, $type, $attr) = @_;
  die "String value expected instead of @{[ref $value]} reference\n" if ref $value;
  return [$name, $attr, SOAP::Utils::encode_data($value)];
}

# Does not include type information
sub as_int {
  my $self = shift;
  my($value, $name, $type, $attr) = @_;
  die "Integer value expected instead of @{[ref $value]} reference\n" if ref $value;
  return [$name, $attr, $value];
}

# Does not include type information
sub as_boolean {
  my $self = shift;
  my($value, $name, $type, $attr) = @_;
  return [$name, $attr, $value ? '1' : '0'];
}

# Does not include type information
sub as_simpledate {
  my $self = shift;
  my($value, $name, $type, $attr) = @_;
  return [$name, $attr, 
    sprintf("%04d-%02d-%02dT00:00:00.0000000+00:00", 
      $value->{year}, $value->{month}, $value->{day})];
}

# Serializes an array of objects in a document/literal format 
sub as_mixed_content{
  my $self = shift;
  my($value, $name, $type, $attr) = @_;

  my $items = "items";
  my @items = map {$self->encode_object($_, $items)} @$value;

  return [$name, $attr, [@items]];
}

}
